Program Listing for File structures.h
↰ Return to documentation for file (codes/cubicle_detect/darknet_ros/structures.h
)
/*
This file is part of spixel.
Spixel is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Foobar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "darknet_ros/stdafx.h"
#include <vector>
#include <memory>
#include <cstdint>
#include <unordered_set>
#include <unordered_map>
//using namespace std;
// Typedefs
typedef std::int16_t sint;
typedef std::uint8_t byte;
typedef cv::Point3d Plane_d;
// Constants
const double eps = 1.0E-6;
const Plane_d zeroPlane = Plane_d(0.0, 0.0, 0.0);
// Border (boundary) types (hinge, coplanarity, etc.)
const int BTCo = 1;
const int BTHi = 2;
const int BTLo = 3;
const int BTRo = 4;
// Border position flags
const byte BLeftFlag = 1;
const byte BRightFlag = 2;
const byte BTopFlag = 4;
const byte BBottomFlag = 8;
// Simple structs and classes
struct BInfo {
int type = 0; // Boundary type BTCo, BTHi, ...
double typePrior = 0; // Prior weight (dep. of type)
int length = 0; // boundary length
int hiCount = 0; // "Length" of boundary (inliers count for hinge)
double coSum = 0.0; // Smo value (sum) for coplanarity
double hiSum = 0.0; // Smo value (sum) for hinge
int coCount = 0;
double sumRow = 0, sumCol = 0; // Sums for plane estimation
double sumRow2 = 0, sumCol2 = 0;
double sumRowCol = 0;
};
// Functions
inline double CalcRegEnergy(double sumRow, double sumCol, double sumRow2, double sumCol2, double size, int numP)
{
double meanRow = (double)sumRow / size;
double meanCol = (double)sumCol / size;
double difSqRow = sumRow2 - 2 * meanRow * sumRow + size * meanRow * meanRow;
double difSqCol = sumCol2 - 2 * meanCol * sumCol + size * meanCol * meanCol;
return (difSqCol + difSqRow) / (size / numP);
}
inline double CalcAppEnergy(double sumR, double sumG, double sumB,
double sumR2, double sumG2, double sumB2, int size, int numP)
{
double meanR = sumR / size;
double meanG = sumG / size;
double meanB = sumB / size;
double difSqR = sumR2 - 2 * meanR * sumR + size * meanR * meanR;
double difSqG = sumG2 - 2 * meanG * sumG + size * meanG * meanG;
double difSqB = sumB2 - 2 * meanB * sumB + size * meanB * meanB;
return (difSqR + difSqG + difSqB) / (size / numP);
}
inline double DotProduct(const Plane_d& p, double x, double y, double z)
{
return x*p.x + y*p.y + z*p.z;
}
template<typename T> T Sqr(const T& a)
{
return a*a;
}
inline double SafeDiv(double a, double b, double aa)
{
return b == 0 ? a / b : aa;
}
void LeastSquaresPlane(double sumIRow, double sumIRow2, double sumICol, double sumICol2, double sumIRowCol, double sumIRowD, double sumIColD,
double sumID, double nI, Plane_d& plane);
// Matrix -- very simple matrix
//template <typename T> struct Matrix;
//template <typename T> struct MatrixIter {
//private:
// Matrix* pMatrix;
// int pos;
//
//public:
// MatrixIter(Matrix* pMatrix_, int pos_) : pMatrix(pMatrix_), pos(pos_) { }
// void operator++() { ++pos; }
// bool operator!=(const MatrixIter& iter2) const { return pos != pos}
//};
template <typename T> struct Matrix {
std::shared_ptr<T> data;
int rows;
int cols;
Matrix() : data(nullptr), rows(0), cols(0) { }
Matrix(int rows_, int cols_) : data(new T[rows_*cols_], [](T* p) { delete[] p; }), rows(rows_), cols(cols_) { }
inline T& operator() (int r, int c)
{
return *(data.get() + r*cols + c);
}
inline const T& operator() (int r, int c) const
{
return *(data.get() + r*cols + c);
}
inline T& operator() (int i) const
{
return *(data.get() + i);
}
inline T* PtrTo(int r, int c)
{
return data.get() + r*cols + c;
}
inline const T* PtrTo(int r, int c) const
{
return data.get() + r*cols + c;
}
const T* begin() const { return data.get(); }
const T* end() const { return data.get() + rows*cols; }
T* begin() { return data.get(); }
T* end() { return data.get() + rows*cols; }
};
// Pixel/Superpixel
struct Pixel;
class Superpixel;
class SuperpixelStereo;
//typedef unordered_map<Superpixel*, BInfo> BInfoMapType;
struct PixelData {
Pixel* p;
double sumRow, sumCol;
double sumRowCol;
double sumRow2, sumCol2;
double sumR, sumG, sumB;
double sumR2, sumG2, sumB2;
double sumDispP, sumDispQ;
int size;
};
typedef std::unordered_map<SuperpixelStereo*, BInfo> BorderDataMap;
// Note: energy deltas below are "energy_before - energy_after"
struct PixelMoveData {
bool allowed; // Operation is allowed, if false, other fields are not valid
Pixel* p; // Moved pixel
Pixel* q; // Neighbor of p
double eRegDelta; // "Regularization" energy delta
double eAppDelta; // "Appearance" energy delta
double eDispDelta; // Deltas of energy terms in Eq. (7)
double eSmoDelta;
double ePriorDelta;
double bLenDelta; // boundary length delta
int pSize; // superpixel of p size
int qSize; // superpixel of q size
PixelData pixelData;
BorderDataMap bDataP, bDataQ;
std::unordered_set<SuperpixelStereo*> prem; // neighbors of superpixel sp which need to be removed
};
struct PixelChangeData {
double newEReg; // new "Regularization" energy
double newEApp; // new "Appearance" energy
int newSize; // new superpixel size
};
struct PixelChangeDataStereo : public PixelChangeData {
double newEDisp;
};
struct Pixel { // : public custom_alloc {
Superpixel* superPixel;
// Geometry info
sint row, col; // pixelsImg position
sint ulr, ulc, lrr, lrc; // coordinates of upper left and lower right corners (in img dimensions)
// Border info (see flags B*Flag above)
byte border;
Pixel() { }
inline void Initialize(sint row_, sint col_, sint ulr_, sint ulc_, sint lrr_, sint lrc_)
{
CV_DbgAssert(ulr_ < lrr_ && ulc_ < lrc_);
row = row_; col = col_;
ulr = ulr_; ulc = ulc_; lrr = lrr_; lrc = lrc_;
border = 0;
superPixel = nullptr;
}
void CalcRowColSum(double& sumRow, double& sumRow2, double& sumCol, double& sumCol2, double& sumRowCol) const
{
sumRow = 0.0; sumRow2 = 0.0;
sumCol = 0.0; sumCol2 = 0.0;
sumRowCol = 0.0;
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
sumRow += i; sumCol += j;
sumRowCol += i*j;
sumRow2 += i*i; sumCol2 += j*j;
if (sumCol2 < 0) {
exit(0);
}
}
}
}
void CalcRGBSum(const cv::Mat& img, double& sumR, double& sumR2, double& sumG, double& sumG2,
double& sumB, double& sumB2) const
{
sumR = 0; sumR2 = 0;
sumG = 0; sumG2 = 0;
sumB = 0; sumB2 = 0;
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
const cv::Vec3d val = img.at<cv::Vec3d>(i, j);
double b = val[0], g = val[1], r = val[2];
// b = img.at<uchar>(i,j); //@hk
sumR += r; sumR2 += r*r;
sumG += g; sumG2 += g*g;
sumB += b; sumB2 += b*b;
}
}
/* sumR /= 255.0;
sumG /= 255.0;
sumB /= 255.0;
sumR2 /= 65025.0; // 65025 = 255*255
sumG2 /= 65025.0;
sumB2 /= 65025.0;
*/
}
/*
double CalcDispSum(const cv::Mat1d& dispImg, const cv::Mat1b& inliers, const Plane_d& plane, double noDisp) const
{
double sumDisp = 0.0;
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
if (inliers(i, j) > 0) {
const double& disp = dispImg(i, j);
double delta = DotProduct(plane, i, j, 1.0) - disp;
sumDisp += delta*delta;
} else {
sumDisp += noDisp;
}
}
}
return sumDisp;
}
*/
double CalcDispSum(const cv::Mat1d& dispImg, const Plane_d& plane, double inlierThresh, double noDisp) const
{
double sumDisp = 0.0;
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
const double& disp = dispImg(i, j);
if (disp > 0) {
double delta = DotProduct(plane, i, j, 1.0) - disp;
if (fabs(delta) < inlierThresh) sumDisp += delta*delta;
else sumDisp += noDisp;
} else {
sumDisp += noDisp;
}
}
}
return sumDisp;
}
/*
void CalcHiSmoothnessSum(byte sideFlag, const cv::Mat1b& inliers, const Plane_d& planep, const Plane_d& planeq,
double& sum, int& count) const
{
sum = 0.0;
count = 0;
if (sideFlag == BLeftFlag) {
for (int i = ulr; i < (int)lrr; i++) {
if (inliers(i, ulc) > 0) {
double ddelta = DotProduct(planep, i, ulc, 1.0) - DotProduct(planeq, i, ulc, 1.0);
sum += ddelta*ddelta;
count++;
}
}
} else if (sideFlag == BRightFlag) {
for (int i = ulr; i < (int)lrr; i++) {
if (inliers(i, lrc - 1) > 0) {
double ddelta = DotProduct(planep, i, lrc - 1, 1.0) - DotProduct(planeq, i, lrc - 1, 1.0);
sum += ddelta*ddelta;
count++;
}
}
} else if (sideFlag == BTopFlag) {
for (int j = ulc; j < (int)lrc; j++) {
if (inliers(ulr, j) > 0) {
double ddelta = DotProduct(planep, ulr, j, 1.0) - DotProduct(planeq, ulr, j, 1.0);
sum += ddelta*ddelta;
count++;
}
}
} else if (sideFlag == BTopFlag) {
for (int j = ulc; j < (int)lrc; j++) {
if (inliers(lrr - 1, j) > 0) {
double ddelta = DotProduct(planep, lrr - 1, j, 1.0) - DotProduct(planeq, lrr - 1, j, 1.0);
sum += ddelta*ddelta;
count++;
}
}
}
}
*/
// Estimate inliers on-the-fly (use when re-estimate boundary data)
void CalcHiSmoothnessSumEI(byte sideFlag,
const cv::Mat1d& depthImg, double inlierThresh,
const Plane_d& planep, const Plane_d& planeq,
double& sum, int& count, int& length) const
{
sum = 0.0;
count = 0;
length = 0;
if (sideFlag == BLeftFlag) {
for (int i = ulr; i < (int)lrr; i++) {
const double& disp = depthImg(i, ulc);
if (disp > 0) {
double pdp = DotProduct(planep, i, ulc, 1.0);
double qdp = DotProduct(planeq, i, ulc, 1.0);
if (fabs(pdp - disp) < inlierThresh && fabs(qdp - disp) < inlierThresh) {
sum += Sqr(pdp - qdp);
count++;
}
}
}
length = lrr - ulr;
} else if (sideFlag == BRightFlag) {
for (int i = ulr; i < (int)lrr; i++) {
const double& disp = depthImg(i, lrc - 1);
if (disp > 0) {
double pdp = DotProduct(planep, i, lrc - 1, 1.0);
double qdp = DotProduct(planeq, i, lrc - 1, 1.0);
if (fabs(pdp - disp) < inlierThresh && fabs(qdp - disp) < inlierThresh) {
sum += Sqr(pdp - qdp);
count++;
}
}
}
length = lrr - ulr;
} else if (sideFlag == BTopFlag) {
for (int j = ulc; j < (int)lrc; j++) {
const double& disp = depthImg(ulr, j);
if (disp > 0) {
double pdp = DotProduct(planep, ulr, j, 1.0);
double qdp = DotProduct(planeq, ulr, j, 1.0);
if (fabs(pdp - disp) < inlierThresh && fabs(qdp - disp) < inlierThresh) {
sum += Sqr(pdp - qdp);
count++;
}
}
}
length = lrc - ulc;
} else if (sideFlag == BTopFlag) {
for (int j = ulc; j < (int)lrc; j++) {
const double& disp = depthImg(lrr - 1, j);
if (disp > 0) {
double pdp = DotProduct(planep, lrr - 1, j, 1.0);
double qdp = DotProduct(planeq, lrr - 1, j, 1.0);
if (fabs(pdp - disp) < inlierThresh && fabs(qdp - disp) < inlierThresh) {
sum += Sqr(pdp - qdp);
count++;
}
}
}
length = lrc - ulc;
}
}
void CalcHiSmoothnessSumEI2(byte sideFlag,
const Plane_d& planep, const Plane_d& planeq,
double& sum, int& count, int& length) const
{
sum = 0.0;
count = 0;
length = 0;
if (sideFlag == BLeftFlag) {
for (int i = ulr; i < (int)lrr; i++) {
double pdp = DotProduct(planep, i, ulc, 1.0);
double qdp = DotProduct(planeq, i, ulc, 1.0);
sum += Sqr(pdp - qdp);
count++;
}
length = lrr - ulr;
} else if (sideFlag == BRightFlag) {
for (int i = ulr; i < (int)lrr; i++) {
double pdp = DotProduct(planep, i, lrc - 1, 1.0);
double qdp = DotProduct(planeq, i, lrc - 1, 1.0);
sum += Sqr(pdp - qdp);
count++;
}
length = lrr - ulr;
} else if (sideFlag == BTopFlag) {
for (int j = ulc; j < (int)lrc; j++) {
double pdp = DotProduct(planep, ulr, j, 1.0);
double qdp = DotProduct(planeq, ulr, j, 1.0);
sum += Sqr(pdp - qdp);
count++;
}
length = lrc - ulc;
} else if (sideFlag == BTopFlag) {
for (int j = ulc; j < (int)lrc; j++) {
double pdp = DotProduct(planep, lrr - 1, j, 1.0);
double qdp = DotProduct(planeq, lrr - 1, j, 1.0);
sum += Sqr(pdp - qdp);
count++;
}
length = lrc - ulc;
}
}
void AddToCoSmoothnessSum(const cv::Mat1d& depthImg, double inlierThresh, const Plane_d& planep, const Plane_d& planeq, double& sum, int& count) const
{
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
const double& disp = depthImg(i, j);
if (disp > 0) {
double pdp = DotProduct(planep, i, j, 1.0);
double qdp = DotProduct(planeq, i, j, 1.0);
if (fabs(pdp - disp) < inlierThresh && fabs(qdp - disp) < inlierThresh) {
sum += Sqr(pdp - qdp);
count++;
}
}
}
}
}
void AddToCoSmoothnessSum(const Plane_d& planep, const Plane_d& planeq, double& sum, int& count) const
{
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
double pdp = DotProduct(planep, i, j, 1.0);
double qdp = DotProduct(planeq, i, j, 1.0);
sum += Sqr(pdp - qdp);
count++;
}
}
}
void SubtractFromCoSmoothnessSum(const cv::Mat1d& depthImg, double inlierThresh, const Plane_d& planep, const Plane_d& planeq, double& sum, int& count) const
{
double sumAdd = 0.0;
int countAdd = 0;
AddToCoSmoothnessSum(depthImg, inlierThresh, planep, planeq, sumAdd, countAdd);
sum -= sumAdd;
count -= countAdd;
}
void AddDispPixels(const cv::Mat1d& dispImg, std::vector<cv::Point3d>& pixels)
{
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
const double& disp = dispImg(i, j);
if (disp > 0.0)
pixels.push_back(cv::Point3d(i, j, disp));
}
}
}
inline void CalcPixelData(const cv::Mat& img, PixelData& pd)
{
pd.p = this;
CalcRowColSum(pd.sumRow, pd.sumRow2, pd.sumCol, pd.sumCol2, pd.sumRowCol);
CalcRGBSum(img, pd.sumR, pd.sumR2, pd.sumG, pd.sumG2, pd.sumB, pd.sumB2);
pd.size = GetSize();
}
inline void CalcPixelDataStereo(const cv::Mat& img, const cv::Mat1d& imgDisp,
Plane_d& planeP, Plane_d& planeQ, double inlierThresh, double noDisp, PixelData& pd)
{
CalcPixelData(img, pd);
pd.sumDispP = CalcDispSum(imgDisp, planeP, inlierThresh, noDisp);
pd.sumDispQ = CalcDispSum(imgDisp, planeQ, inlierThresh, noDisp);
}
//void AddToInlierSums(const cv::Mat1d& dispImg, const cv::Mat1b& inliers,
// int& sumIRow, int& sumIRow2, int& sumICol, int& sumICol2, int& sumIRowCol, double& sumIRowD, double& sumIColD, double& sumID, int& nI)
//{
// for (int i = ulr; i < (int)lrr; i++) {
// for (int j = ulc; j < (int)lrc; j++) {
// if (inliers(i, j) > 0) {
// const double& disp = dispImg(i, j);
// sumIRow += i; sumIRow2 += i*i;
// sumICol += j; sumICol2 += j*j;
// sumIRowCol += i*j;
// sumIRowD += i*disp; sumIColD += j*disp;
// sumID += disp;
// nI++;
// }
// }
// }
//}
void UpdatePPImage(Matrix<Pixel*>& ppImg)
{
for (int i = ulr; i < (int)lrr; i++) {
for (int j = ulc; j < (int)lrc; j++) {
ppImg(i, j) = this;
}
}
}
// Border operations
bool BLeft() const { return (border & BLeftFlag) != 0; }
void SwapBLeft() { border ^= BLeftFlag; }
void SetBLeft() { border |= BLeftFlag; }
bool BRight() const { return (border & BRightFlag) != 0; }
void SwapBRight() { border ^= BRightFlag; }
void SetBRight() { border |= BRightFlag; }
bool BTop() const { return (border & BTopFlag) != 0; }
void SwapBTop() { border ^= BTopFlag; }
void SetBTop() { border |= BTopFlag; }
bool BBottom() const { return (border & BBottomFlag) != 0; }
void SwapBBottom() { border ^= BBottomFlag; }
void SetBBottom() { border |= BBottomFlag; }
void CopyBFlag(byte srcBorder, byte flag) { border = (border & (~flag)) | (srcBorder & flag); }
int GetSize() const { return (lrc - ulc)*(lrr - ulr); }
int GetCSize() const { return lrc - ulc; }
int GetRSize() const { return lrr - ulr; }
int GetBoundaryLength() const { return 2 * (lrc - ulc) + 2 * (lrr - ulr); }
int CountBorderSides() const { return (int)BLeft() + (int)BRight() + (int)BTop() + (int)BBottom(); }
void Split(const cv::Mat& img, int row1, int row2, int col1, int col2, Pixel& p11, Pixel& p12, Pixel& p21, Pixel& p22);
void SplitRow(const cv::Mat& img, int row1, int row2, int col, Pixel& p11, Pixel& p21);
void SplitColumn(const cv::Mat& img, int row, int col1, int col2, Pixel& p11, Pixel& p12);
void CopyTo(const cv::Mat& img, int row, int col, Pixel& p11);
void UpdateInliers(const cv::Mat1d& dispImg, double threshold, cv::Mat1b& inliers) const;
//void AddToInlierSums(const cv::Mat1d& depthImg, const cv::Mat1b& inliers,
// int& sumIRow, int& sumIRow2, int& sumICol, int& sumICol2, int& sumIRowCol, double& sumIRowD, double& sumIColD, double& sumID, int& nI);
std::string GetPixelsAsString();
//CLASS_ALLOCATION()
};
class Superpixel {
public:
int id; // id (index) of superpixel
int borderLength = 0; // length of border (in img pixels)
double sumRow = 0, sumCol = 0; // sum of row, column indices
double sumRowCol = 0; // sum of row * column indices
double sumRow2 = 0, sumCol2 = 0; // sum or row, column squares of indices
double sumR = 0, sumG = 0, sumB = 0; // sum of colors
double sumR2 = 0, sumG2 = 0, sumB2 = 0; // sum of squares of colors
double eApp = 0.0;
double eReg = 0.0;
int size = 0; // number of (image) pixels
int initialSize = 0;
int numP = 0;
public:
Superpixel(int _id) : id(_id) { }
virtual ~Superpixel() { }
// Same as AddPixel below, but energy is not caclulated and must be initialized separately.
// Should only be used in initialization process.
virtual void AddPixelInit(PixelData& pd)
{
sumRow += pd.sumRow;
sumCol += pd.sumCol;
sumRowCol += pd.sumRowCol;
sumRow2 += pd.sumRow2;
sumCol2 += pd.sumCol2;
sumR += pd.sumR;
sumG += pd.sumG;
sumB += pd.sumB;
sumR2 += pd.sumR2;
sumG2 += pd.sumG2;
sumB2 += pd.sumB2;
size += pd.size;
numP++;
pd.p->superPixel = this;
}
// Add a pixel (block) to superpixel.
// Sums of colors (for average color) and coordinates (for center of mass) are updated.
// Note that borderLength is *not* updated and should be set separately!
virtual void AddPixel(PixelData& pd)
{
AddPixelInit(pd);
eApp = CalcAppEnergy(sumR, sumG, sumB, sumR2, sumG2, sumB2, size, numP);
eReg = CalcRegEnergy(sumRow, sumCol, sumRow2, sumCol2, size, numP);
//double eReg2 = regEnergyDebug();
//double dif = eReg - eReg2;
}
/*
double regEnergyDebug()
{
int sumRow = 0, sumCol = 0;
int size = 0;
for (Pixel* pp : pixels) {
size += pp->GetSize();
for (int r = pp->ulr; r < pp->lrr; r++) {
for (int c = pp->ulc; c < pp->lrc; c++) {
sumRow += r;
sumCol += c;
}
}
}
double avgRow = (double)sumRow / size;
double avgCol = (double)sumCol / size;
double result = 0.0;
for (Pixel* pp : pixels) {
for (int r = pp->ulr; r < pp->lrr; r++) {
for (int c = pp->ulc; c < pp->lrc; c++) {
double a = r - avgRow;
double b = c - avgCol;
result += a*a + b*b;
}
}
}
return result;
}
*/
// Remove a pixel (block) from superpixel.
// See comment for AddPixel.
virtual void RemovePixel(const PixelData& pd)
{
sumRow -= pd.sumRow;
sumCol -= pd.sumCol;
sumRowCol -= pd.sumRowCol;
sumRow2 -= pd.sumRow2;
sumCol2 -= pd.sumCol2;
sumR -= pd.sumR;
sumG -= pd.sumG;
sumB -= pd.sumB;
sumR2 -= pd.sumR2;
sumG2 -= pd.sumG2;
sumB2 -= pd.sumB2;
size -= pd.size;
numP--;
eApp = CalcAppEnergy(sumR, sumG, sumB, sumR2, sumG2, sumB2, size, numP);
eReg = CalcRegEnergy(sumRow, sumCol, sumRow2, sumCol2, size, numP);
}
virtual void FinishInitialization()
{
initialSize = size;
RecalculateEnergies();
}
virtual void RecalculateEnergies()
{
eApp = CalcAppEnergy(sumR, sumG, sumB, sumR2, sumG2, sumB2, size, numP);
eReg = CalcRegEnergy(sumRow, sumCol, sumRow2, sumCol2, size, numP);
}
void SetBorderLength(int bl) { borderLength = bl; }
void AddToBorderLength(int bld) { borderLength += bld; }
int GetBorderLength() { return borderLength; }
int GetSize() const { return size; }
int GetInitialSize() const { return initialSize; }
void GetMean(double& meanR, double& meanC) const
{
meanR = (double)sumRow / size;
meanC = (double)sumCol / size;
}
void GetMeanColors(double& r, double& g, double& b) const
{
r = sumR / size;
g = sumG / size;
b = sumB / size;
}
double GetRegEnergy() const
{
return eReg;
}
double GetAppEnergy() const
{
return eApp;
}
void GetRemovePixelData(const PixelData& pd, PixelChangeData& pcd) const;
void GetAddPixelData(const PixelData& pd, PixelChangeData& pcd) const;
};
inline void AddToDSums(double w, double sumRow, double sumCol, double sumRow2, double sumCol2,
double sumRowCol, double size, const Plane_d& plane,
double& sumRowD, double& sumColD, double& sumD) {
sumRowD += w * (sumRow2 * plane.x + sumRowCol * plane.y + sumRow * plane.z);
sumColD += w * (sumRowCol * plane.x + sumCol2 * plane.y + sumCol * plane.z);
sumD += w * (sumRow * plane.x + sumCol * plane.y + size * plane.z);
}
class SuperpixelStereo : public Superpixel {
public:
double sumDisp = 0.0;
double sumIRow = 0, sumICol = 0; // Sum of terms computed for inlier points
double sumIRow2 = 0, sumICol2 = 0;
double sumIRowCol = 0;
double sumIRowD = 0.0, sumIColD = 0.0;
double sumID = 0.0;
int nI = 0;
std::unordered_set<Pixel*> pixels;
BorderDataMap boundaryData;
Plane_d plane;
SuperpixelStereo(int _id) : Superpixel(_id) { }
virtual ~SuperpixelStereo() { }
void AddPixelInit(PixelData& pd) override
{
Superpixel::AddPixelInit(pd);
pixels.insert(pd.p);
}
void AddPixel(PixelData& pd) override
{
Superpixel::AddPixel(pd);
pixels.insert(pd.p);
sumDisp += pd.sumDispQ;
}
void RemovePixel(const PixelData& pd) override
{
Superpixel::RemovePixel(pd);
pixels.erase(pd.p);
sumDisp -= pd.sumDispP;
}
double GetDispSum()
{
return sumDisp;
}
double GetPriorEnergy() const
{
double result = 0.0;
for (auto pair : boundaryData) {
result += pair.second.typePrior;
}
return result;
}
double GetSmoEnergy()
{
double result = 0.0;
for (auto& bdItem : boundaryData) {
const BInfo& bInfo = bdItem.second;
if (bInfo.length > 0) {
if (bInfo.type == BTCo) result += bInfo.coSum / bInfo.coCount; // (size + bdItem.first->size);
else if (bInfo.type == BTHi) result += bInfo.hiSum / bInfo.hiCount;
}
}
return result;
}
void SetPlane(Plane_d& plane);
//void UpdateDispSum(const cv::Mat1d& depthImg, const cv::Mat1b& inliers, double noDisp);
void UpdateDispSum(const cv::Mat1d& depthImg, double inlierThresh, double noDisp);
//void UpdateInlierSums(const cv::Mat1d& depthImg, const cv::Mat1b& inliers);
//void UpdateInliers(const cv::Mat1d& depthImg, double threshold, cv::Mat1b& inliers);
void CalcPlaneLeastSquares(const cv::Mat1d& depthImg);
//void CalcPlaneLeastSquares(SuperpixelStereo* sq, const cv::Mat1d& depthImg);
template<class It, class Pr> void CalcPlaneLeastSquaresI(It from, It to, Pr pred, const cv::Mat1d& depthImg, double weightFactor)
{
double sumIRow = this->sumIRow;
double sumICol = this->sumICol;
double sumIRow2 = this->sumIRow2;
double sumICol2 = this->sumICol2;
double sumIRowCol = this->sumIRowCol;
double sumIRowD = this->sumIRowD;
double sumIColD = this->sumIColD;
double sumID = this->sumID;
double nI = this->nI;
for (; from != to; ++from) {
SuperpixelStereo* sq = pred(from);
if (sq != nullptr) {
double w = weightFactor / (size + sq->size);
sumIRow += w * sq->sumIRow;
sumICol += w * sq->sumICol;
sumIRow2 += w * sq->sumIRow2;
sumICol2 += w * sq->sumICol2;
sumIRowCol += w * sq->sumIRowCol;
sumIRowD += w * sq->sumIRowD;
sumIColD += w * sq->sumIColD;
sumID += w * sq->sumID;
nI += w * sq->nI;
}
}
LeastSquaresPlane(sumIRow, sumIRow2, sumICol, sumICol2, sumIRowCol, sumIRowD, sumIColD, sumID, nI, plane);
}
void CalcPlaneLeastSquaresI(const BorderDataMap& bdMap, const cv::Mat1d& depthImg, double weightFactor, int peblThreshold)
{
double sumIRow = this->sumIRow;
double sumICol = this->sumICol;
double sumIRow2 = this->sumIRow2;
double sumICol2 = this->sumICol2;
double sumIRowCol = this->sumIRowCol;
double sumIRowD = this->sumIRowD;
double sumIColD = this->sumIColD;
double sumID = this->sumID;
double nI = this->nI;
for (auto& bdIter : bdMap) {
if (bdIter.second.type == BTHi) {
//const BInfo& bi = bdIter.second;
//double w = weightFactor / bi.length;
//sumIRow += w * bi.sumRow;
//sumICol += w * bi.sumCol;
//sumIRow2 += w * bi.sumRow2;
//sumICol2 += w * bi.sumCol2;
//sumIRowCol += w * bi.sumRowCol;
//sumIRowD += w * bi.sumRowD;
//sumIColD += w * bi.sumColD;
//sumID += w * bi.sumD;
//nI += w * bi.length;
} else if (bdIter.second.type == BTCo && bdIter.second.length > peblThreshold) {
SuperpixelStereo* sq = bdIter.first;
double w = weightFactor / (size + sq->size);
sumIRow += w * sq->sumIRow;
sumICol += w * sq->sumICol;
sumIRow2 += w * sq->sumIRow2;
sumICol2 += w * sq->sumICol2;
sumIRowCol += w * sq->sumIRowCol;
sumIRowD += w * sq->sumIRowD;
sumIColD += w * sq->sumIColD;
sumID += w * sq->sumID;
nI += w * sq->nI;
}
}
LeastSquaresPlane(sumIRow, sumIRow2, sumICol, sumICol2, sumIRowCol, sumIRowD, sumIColD, sumID, nI, plane);
}
void CalcPlaneLeastSquares(const BorderDataMap& bdMap, const cv::Mat1d& depthImg,
double weightFactorCo, double weightFactorHi, int peblThreshold)
{
double locSumRow = this->sumIRow;
double locSumCol = this->sumICol;
double locSumRow2 = this->sumIRow2;
double locSumCol2 = this->sumICol2;
double locSumRowCol = this->sumIRowCol;
double locSumRowD = this->sumIRowD;
double locSumColD = this->sumIColD;
double locSumD = this->sumID;
double locN = this->nI;
// AddToDSums(1.0, plane, locSumRowD, locSumColD, locSumD);
for (auto& bdIter : bdMap) {
if (bdIter.second.type == BTHi) {
SuperpixelStereo* sq = bdIter.first;
const BInfo& bi = bdIter.second;
double w = weightFactorHi / bi.length;
locSumRow += w * bi.sumRow;
locSumCol += w * bi.sumCol;
locSumRow2 += w * bi.sumRow2;
locSumCol2 += w * bi.sumCol2;
locSumRowCol += w * bi.sumRowCol;
locN += w * bi.length;
::AddToDSums(w, bi.sumRow, bi.sumCol, bi.sumRow2, bi.sumCol2, bi.sumRowCol, bi.length, sq->plane,
locSumRowD, locSumColD, locSumD);
} else if (bdIter.second.type == BTCo && bdIter.second.length > peblThreshold) {
SuperpixelStereo* sq = bdIter.first;
double w = weightFactorCo / (size + sq->size);
locSumRow += w * sumRow;
locSumCol += w * sumCol;
locSumRow2 += w * sumRow2;
locSumCol2 += w * sumCol2;
locSumRowCol += w * sumRowCol;
locN += w * size;
AddToDSums(w, sq->plane, locSumRowD, locSumColD, locSumD);
locSumRow += w * sq->sumRow;
locSumCol += w * sq->sumCol;
locSumRow2 += w * sq->sumRow2;
locSumCol2 += w * sq->sumCol2;
locSumRowCol += w * sq->sumRowCol;
locN += w * sq->size;
sq->AddToDSums(w, sq->plane, locSumRowD, locSumColD, locSumD);
}
}
LeastSquaresPlane(locSumRow, locSumRow2, locSumCol, locSumCol2, locSumRowCol, locSumRowD, locSumColD, locSumD, locN, plane);
}
void AddToDSums(double w, const Plane_d& plane, double& sumRowD, double& sumColD, double& sumD) {
sumRowD += w * (sumRow2 * plane.x + sumRowCol * plane.y + sumRow * plane.z);
sumColD += w * (sumRowCol * plane.x + sumCol2 * plane.y + sumCol * plane.z);
sumD += w * (sumRow * plane.x + sumCol * plane.y + size * plane.z);
}
void ClearPixelSet() { pixels.clear(); }
void AddToPixelSet(Pixel* p1) { pixels.insert(p1); }
void AddToPixelSet(Pixel* p1, Pixel* p2) { pixels.insert(p1); pixels.insert(p2); }
void AddToPixelSet(Pixel* p1, Pixel* p2, Pixel* p3, Pixel* p4)
{
pixels.insert(p1); pixels.insert(p2);
pixels.insert(p3); pixels.insert(p4);
}
void GetRemovePixelDataStereo(const PixelData& pd, PixelChangeDataStereo& pcd) const;
void GetAddPixelDataStereo(const PixelData& pd, PixelChangeDataStereo& pcd) const;
// For debug purposes!
double CalcDispEnergy(const cv::Mat1d& dispImg, double inlierThresh, double noDisp);
void CheckAppEnergy(const cv::Mat& img);
void CheckRegEnergy();
};
// Simple Union-Find disjont set of integers (i.e., equivalence classes)
// implementation using a vector
// TODO optimize a bit Find if necessary.
class UnionFind {
protected:
std::vector<int> vector;
public:
UnionFind(int size)
{
vector.resize(size, -1); // -1 is size of each
}
void Union(int e1, int e2)
{
e1 = Find(e1);
e2 = Find(e2);
if (e1 == e2)
return;
int size1 = -vector[e1];
int size2 = -vector[e2];
if (size1 < size2) { vector[e1] = e2; vector[e2] = -(size1 + size2); }
else { vector[e2] = e1; vector[e1] = -(size1 + size2); }
}
inline int Find(int e)
{
int root = e;
while (vector[root] >= 0) root = vector[root];
if (e != root) {
while (vector[e] != root) {
int tmpe = vector[e];
vector[e] = root;
e = tmpe;
}
}
return root;
}
inline int Size(int e)
{
return -vector[Find(e)];
}
};
// Functions
// Return Pixel at (row, col), nullptr if coordinates are invalid
inline const Pixel* PixelAt(const Matrix<Pixel>& pixelsImg, int row, int col)
{
if (row >= 0 && row < pixelsImg.rows && col >= 0 && col < pixelsImg.cols) return pixelsImg.PtrTo(row, col);
else return nullptr;
}
inline Pixel* PixelAt(Matrix<Pixel>& pixelsImg, int row, int col)
{
if (row >= 0 && row < pixelsImg.rows && col >= 0 && col < pixelsImg.cols) return pixelsImg.PtrTo(row, col);
else return nullptr;
}
//inline double GetPriorEnergy(const unordered_map<Superpixel*, BInfo>& boundaryData)
//{
// double result = 0.0;
//
// for (auto pair : boundaryData) {
// result += pair.second.prior;
// }
// return result;
//}